#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "ThreadPool.hpp"

#define DEFAULT_PORT 8080
#define BACK_LOG 5
#define THREAD_NUM 5

struct Info
{
  int _port;
  std::string _ip;
  int _sock;

  Info(int port, std::string ip, int sock)
    :_port(port)
     ,_ip(ip)
     ,_sock(sock)
  {}
};

class TcpServer
{
public:
  TcpServer(int port = DEFAULT_PORT)
    :_port(port)
     ,_listen_sock(-1)
     ,_tp(nullptr)
  {}
  bool TcpServerInit()
  {
    // 创建套接字
    _listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (_listen_sock < 0){
      std::cerr << "socket creat fail" << std::endl;
      return false;
    }
    std::cout << "socket creat succes, sock: " << _listen_sock << std::endl;
    // 绑定
    struct sockaddr_in local;
    memset(&local, 0, sizeof(local));

    local.sin_family = AF_INET;
    local.sin_port = htons(_port);
    local.sin_addr.s_addr = INADDR_ANY;
    
    if (bind(_listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0){
      std::cout << "bind fail" << std::endl;
      return false;
    }
    std::cout << "bind success" << std::endl;
    
    // 将套接字设置为监听状态
    if (listen(_listen_sock, BACK_LOG) < 0){
      std::cout << "listen fail" << std::endl;
    }
    std::cout << "listen success" << std::endl;
    
    return true;
  }
  void loop()
  {
    struct sockaddr_in peer;// 获取远端端口号和ip信息
    socklen_t len = sizeof(peer);
    _tp = new ThreadPool(THREAD_NUM); 
    _tp->ThreadPoolInit();
    while (1){
      // 获取链接
      // sock 是进行通信的一个套接字  _listen_sock 是进行监听获取链接的一个套接字
      int sock = accept(_listen_sock, (struct sockaddr*)&peer, &len);
      if (sock < 0){
        std::cout << "accept fail, continue accept" << std::endl;
        continue;
      }
      int peerPort = ntohs(peer.sin_port);
      std::string peerIp = inet_ntoa(peer.sin_addr);
      std::cout << "get a new link, [" << peerIp << "]:[" << peerPort  << "]"<< std::endl;
      Task* task = new Task(peerPort, peerIp, sock);
      _tp->Put(task);
    }
  }
  ~TcpServer()
  {
    if (_listen_sock >= 0) close(_listen_sock);
  }
private:
  int _port;
  int _listen_sock;
  ThreadPool* _tp;
};
